home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 398 / 398.xpi / chrome / forecastfox.jar / content / parser / parser-service.js < prev    next >
Text File  |  2010-02-04  |  23KB  |  766 lines

  1. /*------------------------------------------------------------------------------
  2.   Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
  3.   ----------------------------------------------------------------------------*/
  4.   
  5. /******************************************************************************
  6.  * Get the selected forecastfox locale.
  7.  *
  8.  * @return  The locale name.
  9.  ******************************************************************************/
  10. function getLocale()
  11. {
  12.   var reg = Cc["@mozilla.org/chrome/chrome-registry;1"].
  13.             getService(Ci.nsIXULChromeRegistry);
  14.   return reg.getSelectedLocale("forecastfox");
  15. }
  16.   
  17. /******************************************************************************
  18.  * Evaluate the data and return the correct data type.
  19.  *
  20.  * @param   The data type.
  21.  * @param   The value.
  22.  * @return  The value in the correct javascript data type.
  23.  ******************************************************************************/
  24. function evalData(aType, aData)
  25. {
  26.   var rv = "";
  27.   switch (aType) {
  28.  
  29.   //integer data type
  30.   case "Int":
  31.     rv = (aData == null) ? 0 : Number(aData);
  32.     break;
  33.       
  34.   //boolean data type
  35.   case "Bool":
  36.     rv = (aData == null) ? false : Boolean(Number(aData));
  37.     break;
  38.     
  39.   //string data type
  40.   case "Char":
  41.   default:
  42.     rv = (aData == null) ? "" : String(aData);
  43.     break;
  44.   }
  45.     
  46.   //return the data
  47.   return rv;
  48. }
  49.     
  50. /******************************************************************************
  51.  * Interfaces used by a service for parsing the weather feed.  Supplies a set
  52.  * items and methods used for manipulating the data.  Targets are stored as a
  53.  * flat list with an id made up of the target and the index with path and group
  54.  * properties.  Items are stored in a flat list in a group object.  The id is
  55.  * made up of the group and item name.  The group property on the target
  56.  * is used to retrieve the group object which has the items.  Data is stored 
  57.  * in a flat list of target, index, and item name.
  58.  * 
  59.  * @status    FROZEN
  60.  * @version   1.0
  61.  ******************************************************************************/
  62. function ParserService() 
  63. {  
  64.   //setup a new error
  65.   this._error = Cc["@ensolis.com/forecastfox/error-item;1"].
  66.                 createInstance(Ci.ffIErrorItem);    
  67. }
  68. ParserService.prototype = {
  69.   __proto__: new ServiceBase("ParserService"),
  70.   _dskSvc: null,
  71.   _cnvSvc: null,
  72.   _prfSvc: null,
  73.   _file: null,
  74.   _items: null,
  75.   _data: null,
  76.   _hasData: null,
  77.   _resolver: null,
  78.   _locale: null,
  79.               
  80.   ////////////////////////////////
  81.   // ffIService
  82.           
  83.   /**
  84.    * Initialize the component.  Called by the manager service.
  85.    */    
  86.   start: function ParserService_start()
  87.   {
  88.     //setup the variables
  89.     this._items = {};
  90.     this._data = {};
  91.     this._hasData = false;   
  92.     this._locale = getLocale();
  93.       
  94.     //get the disk and conversion services
  95.     var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
  96.                  getService(Ci.ffIManagerService);
  97.     this._dskSvc = mgrSvc.disk;
  98.     this._cnvSvc = mgrSvc.converters;
  99.     
  100.     //get the profile service so the [prof] variable can use it
  101.     this._prfSvc = mgrSvc.profiles;
  102.     
  103.     //get the xpath resolver
  104.     this._resolver = Cc["@ensolis.com/forecastfox/resolver-item;1"].
  105.                      createInstance(Ci.nsIDOMXPathNSResolver);
  106.     
  107.     //set the feed namespace                 
  108.     if (this._resolver instanceof Ci.ffIItem)
  109.       this._resolver.setProperty("adc", "http://www.accuweather.com");
  110.     
  111.     //get the parser file
  112.     this._file = this._dskSvc.get("parser.js", TYPE_DEFAULTS);
  113.     
  114.     //load the data
  115.     return this._loadParser();
  116.   },
  117.   
  118.   /**
  119.    * Destroy the component.  Called by the manager service.  This may be
  120.    * called prior to start so it needs to be safe.
  121.    */  
  122.   stop: function ParserService_stop()
  123.   {
  124.     //clear variables
  125.     this._dskSvc = null;
  126.     this._cnvSvc = null;
  127.     this._prfSvc = null;
  128.     this._file = null;
  129.     this._items = null;   
  130.     this._data = null;
  131.     this._hasData = null;
  132.     this._resolver = null;
  133.     this._locale = null; 
  134.   },
  135.               
  136.   ////////////////////////////////
  137.   // ffIParserService
  138.     
  139.   /**
  140.    * Last modified date of datasource.
  141.    */
  142.   get lastModified() { 
  143.     if (!this._file || !this._file.exists())
  144.       return 0;
  145.     else
  146.       return this._file.lastModifiedTime;
  147.   },
  148.       
  149.   /**
  150.    * Parse the DOM document supplied by the feed.  Returns false if 
  151.    * parsing failed.  Use lastError attribute to obtain more detailed
  152.    * error information.
  153.    * 
  154.    * @param  The DOM document to parse.
  155.    * @return False if parsing failed.
  156.    */
  157.   parseDOM: function ParserService_parseDOM(aDocument)
  158.   {        
  159.     //reset the data variable
  160.     this._data = {};
  161.     this._hasData = false;
  162.       
  163.     //setup error variables
  164.     const PREFIX = "ff.parser.dom.";
  165.     var name = "";
  166.     var message = "";
  167.     
  168.     //check that the parser is loaded
  169.     if (!this._items.hasOwnProperty("targets")) {
  170.       name = this.bundle.GetStringFromName(PREFIX + "loaded.name");
  171.       message = this.bundle.GetStringFromName(PREFIX + "loaded.message");
  172.       this._error.init(SEVERITY_ERROR, name, message);
  173.       return false;
  174.     }
  175.           
  176.     //error if document is not well formed
  177.     if (!this._dskSvc.validate(aDocument, "adc_database")) {
  178.       name = this.bundle.GetStringFromName(PREFIX + "valid.name");
  179.       message = this.bundle.GetStringFromName(PREFIX + "valid.message");
  180.       this._error.init(SEVERITY_ERROR, name, message);
  181.       return false;
  182.     }
  183.                 
  184.     //check for error messages
  185.     var node = this._evalPath("./adc:failure", aDocument);
  186.     if (node) {
  187.       name = node.textContent;
  188.       message = node.textContent;
  189.       this._error.init(SEVERITY_ERROR, name, message);
  190.       return false;
  191.     }
  192.         
  193.     //loop through the targets
  194.     for (var id in this._items.targets) {
  195.       var target = this._items.targets[id];
  196.       
  197.       //get the items for the target and the context node
  198.       var items = this._items.groups[target.group];
  199.       node = this._evalPath(target.path, aDocument.documentElement);
  200.       
  201.       //loop through the items and evaluate
  202.       for (var id2 in items) {
  203.         var id3 = target.name + "-" + String(target.index) + "-" + id2;
  204.         this._data[id3] = this._evalItem(items[id2], node);
  205.       }
  206.     } 
  207.             
  208.     //parse was successful
  209.     this._hasData = true;
  210.     return true;    
  211.   },
  212.      
  213.   /**
  214.    * Serialize the parsed document to javascript source.  Used to cache
  215.    * the parser items.  Use the parseCache function to read the cache.
  216.    * Returns false if serializing failed.  Use lastError attribute 
  217.    * to obtain more detailed error information.
  218.    * 
  219.    * @param  The file to serialize to.
  220.    * @return False if serialize failed.
  221.    */
  222.   serializeCache: function ParserService_serializeCache(aCache)
  223.   {
  224.     //setup error variables
  225.     const PREFIX = "ff.parser.serialize.";
  226.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  227.     var message = "";
  228.       
  229.     //no data stored
  230.     if (!this._hasData) {
  231.       message = this.bundle.GetStringFromName(PREFIX + "empty.message");
  232.       this._error.init(SEVERITY_WARNING, name, message);      
  233.       return false;
  234.     }
  235.     
  236.     //cache file is not writable
  237.     if ((aCache.exists() && !aCache.isWritable()) ||
  238.         (!aCache.exists() && !aCache.parent.isWritable())) {
  239.       message = this.bundle.formatStringFromName(PREFIX + "write.message", 
  240.                                                  [aCache.path], 1);
  241.       this._error.init(SEVERITY_ERROR, name, message);      
  242.       return false;
  243.     }
  244.           
  245.     //convert the items to javascript source
  246.     var content = this._data.toSource();
  247.     
  248.     //write to the cache
  249.     this._dskSvc.writeText(aCache, content, false, false, false);
  250.     return true;
  251.   },
  252.       
  253.   /**
  254.    * Parse the cached parser items.  Returns false if 
  255.    * parsing failed.  Use lastError attribute to obtain more detailed
  256.    * error information.
  257.    * 
  258.    * @param  The cache file.
  259.    * @return False if parsing failed.
  260.    */
  261.   parseCache: function ParserService_parseCache(aCache)  
  262.   {    
  263.     //reset the data variable
  264.     this._data = {};
  265.     this._hasData = false;
  266.       
  267.     //setup error variables
  268.     const PREFIX = "ff.parser.cache.";
  269.     var name = "";
  270.     var message = "";
  271.       
  272.     //check that the cache file exists
  273.     if (!aCache.exists()) {
  274.       name = this.bundle.GetStringFromName(PREFIX + "exists.name");
  275.       message = this.bundle.GetStringFromName(PREFIX + "exists.message");
  276.       this._error.init(SEVERITY_ERROR, name, message);
  277.       return false;
  278.     }
  279.       
  280.     //check that the cache file is readable
  281.     if (!aCache.isReadable()) {
  282.       name = this.bundle.GetStringFromName(PREFIX + "read.name");
  283.       message = this.bundle.formatStringFromName(PREFIX + "read.message", 
  284.                                                  [aCache.path], 1);
  285.       this._error.init(SEVERITY_ERROR, name, message);
  286.       return false;
  287.     }
  288.     
  289.     //read the cache
  290.     var content = this._dskSvc.readText(aCache);
  291.     if (!content) {
  292.       name = this.bundle.GetStringFromName(PREFIX + "content.name");
  293.       message = this.bundle.GetStringFromName(PREFIX + "content.message");
  294.       this._error.init(SEVERITY_ERROR, name, message);
  295.       return false;
  296.     }
  297.         
  298.     /** check that the cache is older than the parser.  This needs to be
  299.         done after reading the cache because there could have been 
  300.         outstanding file writes which the read will force to occur. **/
  301.     if (this.lastModified > aCache.lastModifiedTime) {
  302.       name = this.bundle.GetStringFromName(PREFIX + "last.name");
  303.       message = this.bundle.GetStringFromName(PREFIX + "last.message");
  304.       this._error.init(SEVERITY_ERROR, name, message);
  305.       return false;
  306.     }
  307.         
  308.     //set items
  309.     try {
  310.       this._data = eval(content);
  311.     } catch(e) {
  312.       this._data = {};
  313.       this._error.init(SEVERITY_ERROR, e.name, e.message);
  314.       return false;  
  315.     }
  316.     
  317.     //parse was successful
  318.     this._hasData = true;
  319.     return true;
  320.   },
  321.     
  322.   /**
  323.    * Parser has a specific item.  Use the target, index, and item name 
  324.    * separated by hyphens as the id of the item.
  325.    * 
  326.    * @param   ID of the parser item.
  327.    * @return  True if item exists.
  328.    */
  329.   hasItem: function ParserService_hasItem(aID)
  330.   {
  331.     //split the id into its parts
  332.     var unique = aID.split("-");
  333.     
  334.     //check that we have the target
  335.     var id = unique[0] + "-" + unique[1];
  336.     if (!this._items.targets.hasOwnProperty(id))
  337.       return false;
  338.       
  339.     //check actual item
  340.     var target = this._items.targets[id];
  341.     var items = this._items.groups[target.group];
  342.     if (items.hasOwnProperty(unique[2]))
  343.       return true;
  344.  
  345.     //check global items
  346.     target = this._items.targets["global-0"];
  347.     items = this._items.groups[target.group];
  348.     return items.hasOwnProperty(unique[2]);
  349.   },
  350.                            
  351.   /**
  352.    * Retrieve a parser item returns null if item doesn't exist.
  353.    * Use the target, index, and item name separated by hyphens 
  354.    * as the id of the item.
  355.    * 
  356.    * @param   ID of the parser item.
  357.    * @return  A ffIParserItem.
  358.    */
  359.   getItem: function ParserService_getItem(aID)
  360.   {
  361.     //split the id into its parts
  362.     var unique = aID.split("-");
  363.     
  364.     //check that we have the target
  365.     var id = unique[0] + "-" + unique[1];    
  366.     if (!this._items.targets.hasOwnProperty(id))
  367.       return null;
  368.       
  369.     //check actual item
  370.     var target = this._items.targets[id];
  371.     var items = this._items.groups[target.group];
  372.     if (items.hasOwnProperty(unique[2]))
  373.       return this._createItem(items[unique[2]], target);
  374.  
  375.     //check global items
  376.     target = this._items.targets["global-0"];
  377.     items = this._items.groups[target.group];
  378.     if (items.hasOwnProperty(unique[2]))
  379.       return this._createItem(items[unique[2]], target);
  380.     
  381.     //item was not found
  382.     return null;
  383.   },
  384.   
  385.   /**
  386.    * Retrieve an array of parser items.
  387.    * 
  388.    * @param   Target of the item.
  389.    * @param   Index of the item.
  390.    * @param   Count of items in the array.
  391.    * @return  An array of ffIParserItem components.
  392.    */
  393.   getItems: function ParserService_getItems(aTarget, aIndex, aCount)
  394.   {
  395.     //do globals first
  396.     var rv = [];
  397.     var target = this._items.targets["global-0"];
  398.     var items = this._items.groups[target.group];
  399.          
  400.     //loop through the items
  401.     for (var id in items) {
  402.       var item = items[id];
  403.       
  404.       //skip hidden items
  405.       if (item.hasOwnProperty("hidden"))
  406.         continue;
  407.       
  408.       //add the items
  409.       var id2 = target.name + "-" + String(target.index) + "-" + id;
  410.       rv.push(this.getItem(id2));
  411.     }
  412.     
  413.     //check the specific target
  414.     id = aTarget + "-" + String(aIndex);
  415.     if (!this._items.targets.hasOwnProperty(id) || aTarget == "global") {
  416.       aCount.value = rv.length;
  417.       return rv; 
  418.     }
  419.     
  420.     //get the target data
  421.     target = this._items.targets[id];
  422.     items = this._items.groups[target.group];
  423.     
  424.     //loop through the items
  425.     for (id in items) {
  426.       item = items[id];
  427.       
  428.       //skip hidden items
  429.       if (item.hasOwnProperty("hidden"))
  430.         continue;
  431.         
  432.       //add the items
  433.       id2 = target.name + "-" + String(target.index) + "-" + id;
  434.       rv.push(this.getItem(id2));
  435.     }
  436.  
  437.     //return the array
  438.     aCount.value = rv.length;
  439.     return rv; 
  440.   },
  441.   
  442.   /**
  443.    * Retrieve the value of a parser item.  Pass in a 
  444.    * converter name to use in the conversion process 
  445.    * or null for the default value.
  446.    * 
  447.    * @param   Target of the item.
  448.    * @param   Index of the item.
  449.    * @param   Name of the item.
  450.    * @param   Name of the converter or null.
  451.    * @return  The formatted value of the item.
  452.    */
  453.   getValue: function ParserService_getValue(aTarget, aIndex, aName, aConverter)
  454.   {
  455.     var item = null;
  456.     
  457.     //check that we have the target
  458.     var id = aTarget + "-" + String(aIndex);
  459.     if (!this._items.targets.hasOwnProperty(id))
  460.       return null;
  461.       
  462.     //check actual item
  463.     var target = this._items.targets[id];
  464.     var items = this._items.groups[target.group];
  465.     if (items.hasOwnProperty(aName))
  466.       item = items[aName];
  467.     else {
  468.  
  469.       //check global items
  470.       target = this._items.targets["global-0"];
  471.       items = this._items.groups[target.group];
  472.       if (items.hasOwnProperty(aName))
  473.         item = items[aName];
  474.     }
  475.     
  476.     //item was not found
  477.     if (!item)
  478.       return null;
  479.       
  480.     //return an N/A if data doesn't exist
  481.     id = target.name + "-" + String(target.index) + "-" + item.name;
  482.     if (!this._data.hasOwnProperty(id))
  483.       return "N/A";
  484.           
  485.     //no data so return the value
  486.     var value = this._data[id];
  487.     if (value == "N/A")
  488.       return value;
  489.       
  490.     /** 
  491.      * calculations are always ran first to get the correct
  492.      * javascript context.
  493.      */
  494.     var comp = this;
  495.     if (item.hasOwnProperty("calc")) {
  496.       var calc = item.calc;
  497.       calc = calc.replace(/\$VAL/g, "'" + String(value) + "'"); 
  498.       try {
  499.         value = eval(calc);
  500.       } catch(e) {}     
  501.     }
  502.     
  503.     /** if we are being called recursively return early so we do not convert 
  504.         the same value multiple times. **/
  505.     if (Components.stack.caller.name == "ParserService_getValue")
  506.       return value;
  507.            
  508.     //use the conversion service
  509.     if (item.hasOwnProperty("conversion"))
  510.       value = this._cnvSvc.formatValue(item.conversion, aConverter, value);    
  511.       
  512.     //return the final value
  513.     return value;    
  514.   },
  515.     
  516.   /**
  517.    * Builds a label from the passed in string.  If the label has a "+" within
  518.    * a parser name it will be split and the remaining will be used to retrieve
  519.    * the converter to use for that value.  This allows multiple uom to be 
  520.    * displayed for an item.
  521.    * 
  522.    * @param   The label string to format.
  523.    * @param   Target of the item or null.
  524.    * @param   Index of the item or null. 
  525.    * @return  The formatted label.   
  526.    */
  527.   getLabel: function ParserService_getLabel(aLabel, aTarget, aIndex)    
  528.   {
  529.     //nothing has been parsed
  530.     if (!this._hasData)
  531.       return ""; 
  532.     
  533.     //function used to replace
  534.     var comp = this;
  535.     function getLabel_replace(aContent) {
  536.     
  537.       //get the string text
  538.       var text = aContent.substring(1, aContent.length -1);
  539.       text = text.split("+");
  540.         
  541.       //get the item and converter names
  542.       var name = text[0];
  543.       var converter = null;      
  544.       if (text.length > 1)
  545.         converter = text[1];
  546.         
  547.       //create the item id and see if we have it
  548.       var value = comp.getValue(aTarget, aIndex, name, converter);
  549.       if (value != null)
  550.         return value;
  551.       else
  552.         return text;  
  553.     }
  554.     
  555.     //do the replace
  556.     var label = aLabel;
  557.     try {
  558.       label = aLabel.replace(/\[[^\[\]]+\]/g, getLabel_replace);
  559.     } catch (e) {}
  560.     
  561.     //return the formatted label
  562.     getLabel_replace = null;
  563.     return label;
  564.   },
  565.               
  566.   ////////////////////////////////
  567.   // Internal Functions  
  568.   
  569.   /**
  570.    * Evaluate an xpath expression.  Use the node as the context to
  571.    * evaluate the expression in.
  572.    *
  573.    * @param   Expression to evaluate.   
  574.    * @param   Context node.
  575.    * @return  A DOM node result.
  576.    */
  577.   _evalPath: function ParserService__evalPath(aExpr, aNode)
  578.   {
  579.     //get the document
  580.     var doc;
  581.     try {
  582.       doc = (aNode.ownerDocument == null) ? aNode : aNode.ownerDocument;
  583.     } catch(e) {
  584.       this._dskSvc.log("Error evaluating xpath.", e, null);
  585.       return null;
  586.     }
  587.     
  588.     //evaluate the expression 
  589.     var result = null;
  590.     try {   
  591.       var results = doc.evaluate(aExpr, aNode, this._resolver, 
  592.                                  Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, 
  593.                                  null);
  594.       result = results.snapshotItem(0); 
  595.     } catch(e) {}
  596.     
  597.     //return the variable
  598.     return result;    
  599.   },
  600.   
  601.   /**
  602.    * Evaluate an item to get the data from the feed.
  603.    *
  604.    * @param   The item to evaluate.
  605.    * @param   The context node.
  606.    * @return  The evaluated data.
  607.    */
  608.   _evalItem: function ParserService__evalItem(aItem, aContext)
  609.   {          
  610.     //get the data type
  611.     var type = aItem.type;
  612.     
  613.     //no path so return empty data
  614.     if (!aItem.hasOwnProperty("path"))
  615.       return evalData(type, null);
  616.     else
  617.       var path = aItem.path;
  618.       
  619.     //process the prepath
  620.     var node = null;
  621.     if (aItem.hasOwnProperty("prepath")) {
  622.       node = this._evalPath(aItem.prepath, aContext);
  623.       if (!node)
  624.         path = path.replace(/\$PRE/g, "''");
  625.       else
  626.         path = path.replace(/\$PRE/g, node.textContent);
  627.     } else
  628.       path = path.replace(/\$PRE/g, "''");
  629.    
  630.     //process the path
  631.     node = this._evalPath(path, aContext);
  632.     if (!node)
  633.       return evalData(type, null);
  634.  
  635.     //return the value
  636.     return (node.textContent == "N/A") ? "N/A" : 
  637.            evalData(type, node.textContent);
  638.   },
  639.   
  640.   /**
  641.    * Translate given feed data in to localized values.
  642.    *
  643.    * @param  Target of the item to translate.
  644.    * @param  Index of the item to translate.
  645.    * @param  Name of the item to translate.
  646.    * @param  Converter name for getValue call.
  647.    * @return The localized version of the feed data.
  648.    */
  649.   _translate: function ParserService__translate(aTarget, aIndex, aName, aConverter)
  650.   {
  651.     var value = null;
  652.     const PREFIX = "ff.parser.";
  653.     
  654.     //translate forecast based on icon
  655.     if (aName == "t" || aName == "tlong") {
  656.     
  657.       //if we are using an English locale, then just use the feed's data.
  658.       if (this._locale.match("en-"))
  659.         return this.getValue(aTarget, aIndex, aName + "_en", aConverter);
  660.     
  661.       //international version... so get the icon and then return the corresponding string.
  662.       value = this.getValue(aTarget, aIndex, "icon", aConverter);
  663.       return this.bundle.GetStringFromName(PREFIX + "forecast." + value);
  664.     }
  665.     
  666.     ///translate all others based on the code value  
  667.     value = this.getValue(aTarget, aIndex, aName + "code", aConverter);
  668.     
  669.     //change to lower case and replace space with underscore
  670.     value = value.toLowerCase().replace(/\//g, "");
  671.     value = value.replace(/\s/g, "_");
  672.       
  673.     //get the translation
  674.     try {
  675.       value = this.bundle.GetStringFromName(PREFIX + aName + "." + value);
  676.     } catch(e) {}  
  677.     
  678.     //return the value
  679.     return value;
  680.   },
  681.   
  682.   /**
  683.    * Create a parser item from a javascript object 
  684.    * representing that item.
  685.    *
  686.    * @param   The javascript representation of the item.
  687.    * @param   The target of the item.
  688.    * @return  The parser item.
  689.    */
  690.   _createItem: function ParserService__createItem(aItem, aTarget)
  691.   {
  692.     //create an empty parser item
  693.     var item = Cc["@ensolis.com/forecastfox/parser-item;1"].
  694.                createInstance(Ci.ffIParserItem);
  695.                
  696.     //loop through the properties
  697.     for (var property in aItem)
  698.       item.setProperty(property, aItem[property]);
  699.     
  700.     //set the target based properties
  701.     item.setProperty("target", aTarget.name);
  702.     item.setProperty("index", aTarget.index);
  703.     var id = item.target + "-" + String(item.index) + "-" + item.name;
  704.     item.setProperty("ID", id);
  705.     
  706.     //get description
  707.     var alias = item.getProperty("alias");
  708.     alias = (alias != null) ? alias : item.name;
  709.     var description = item.name; 
  710.     try {
  711.       description = this.bundle.GetStringFromName("ff.parser." + alias);
  712.     } catch(e) {}
  713.     item.setProperty("description", description);
  714.     
  715.     //return the item
  716.     return item;
  717.   },
  718.   
  719.   /**
  720.    * Load the parser data from file.
  721.    *
  722.    * @return  False if the load fails.
  723.    */
  724.   _loadParser: function ParserService__loadParser()
  725.   {                
  726.     //setup error variables
  727.     const PREFIX = "ff.parser.load.";
  728.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  729.     var message = "";
  730.                           
  731.     //file doesn't exist
  732.     if (!this._file.exists()) {
  733.       message = this.bundle.GetStringFromName(PREFIX + "exists.message");
  734.       this._error.init(SEVERITY_ERROR, name, message);
  735.       return false;
  736.     }
  737.                           
  738.     //file is not readable
  739.     if (!this._file.isReadable()) {
  740.       message = this.bundle.formatStringFromName(PREFIX + "read.message",
  741.                                                  [this._file.path], 1);
  742.       this._error.init(SEVERITY_ERROR, name, message);
  743.       return false;
  744.     }
  745.           
  746.     //get the content of the file
  747.     var content = this._dskSvc.readText(this._file);
  748.     if (!content) {
  749.       message = this.bundle.GetStringFromName(PREFIX + "empty.message");
  750.       this._error.init(SEVERITY_ERROR, name, message);
  751.       return false;
  752.     }
  753.     
  754.     //save the data in the items variable 
  755.     try {
  756.       this._items = eval(content);
  757.     } catch(e) {
  758.       this._items = {};
  759.       this._error.init(SEVERITY_ERROR, name, e.message);
  760.       return false;
  761.     }
  762.  
  763.     //loaded successfully
  764.     return true;
  765.   }                                            
  766. };